package com.hube.platform.tenant.configuration;

import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import com.hube.platform.tenant.exception.ApplicationException;
import com.hube.platform.tenant.configuration.response.Response;
import io.swagger.annotations.ApiModelProperty;
import org.apache.commons.lang3.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.nio.file.AccessDeniedException;
import java.util.List;

/**
 * 全局异常拦截
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    private final static String DEFAULT_ERROR_MESSAGE = "系统繁忙请稍后重试";

    private final static String DEFAULT_INVALID_FORMAT_ERROR_MESSAGE = "参数异常";

    private final static Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 应用异常
     */
    @ExceptionHandler(value = ApplicationException.class)
    @ResponseBody
    public Response<Object> applicationExceptionHandler(HttpServletRequest req, ApplicationException e) {
        handlerErrorMessage(e);
        return Response.error(e.getCode(), e.getMessage());
    }

    /**
     * Spring validation
     */
    @ExceptionHandler(value = BindException.class)
    @ResponseBody
    public Response<Object> validationErrorHandler(HttpServletRequest req, BindException e) {
        handlerErrorMessage(e);
        return Response.error(HttpStatus.BAD_REQUEST.value(), e.getAllErrors().get(0).getDefaultMessage());
    }


    /**
     * 拒绝访问
     */
    @ExceptionHandler({AccessDeniedException.class})
    public Response<Object> accessDeniedException(AccessDeniedException e) {
        handlerErrorMessage(e);
        return Response.error(HttpStatus.FORBIDDEN.value(), e.getMessage());
    }

    /**
     * 异常拦截
     *
     * @param e
     * @return
     */
    @ExceptionHandler({InvalidFormatException.class})
    public Response<Object> invalidFormatException(InvalidFormatException e) {
        handlerErrorMessage(e);
        List<JsonMappingException.Reference> path = e.getPath();
        String errors = "";
        if (ObjectUtils.isNotEmpty(path) && path.size() == 3) {
            Class<?> aClass;
            try {
                JsonMappingException.Reference reference = path.get(2);
                Object from = reference.getFrom();
                aClass = from.getClass();
                Field fileErrorName = aClass.getDeclaredField(reference.getFieldName());
                ApiModelProperty apiModelProperty = fileErrorName.getAnnotation(ApiModelProperty.class);
                errors = apiModelProperty.value();
            } catch (Exception exception) {
                exception.printStackTrace();
            }
        }
        return Response.error(HttpStatus.BAD_REQUEST.value(), errors + DEFAULT_INVALID_FORMAT_ERROR_MESSAGE);
    }

    /**
     * 参数异常
     */
    @ExceptionHandler({HttpMessageNotReadableException.class})
    public Response<Object> httpMessageNotReadableException(HttpMessageNotReadableException e) {
        handlerErrorMessage(e);
        if (e.getCause() instanceof InvalidFormatException) {
            return invalidFormatException((InvalidFormatException) e.getCause());
        } else {
            return Response.error(HttpStatus.BAD_REQUEST.value(), DEFAULT_INVALID_FORMAT_ERROR_MESSAGE);
        }

    }


    /**
     * 其他错误拦截
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public Response<Object> normalErrorHandler(HttpServletRequest req, Exception e) {
        handlerErrorMessage(e);
        if (e instanceof ApplicationException) {
            return Response.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage());
        }
        return Response.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), DEFAULT_ERROR_MESSAGE);
    }

    /**
     * 处理所有接口数据验证异常
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public Response<Object> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
        BindingResult bindingResult = ex.getBindingResult();
        return Response.error(HttpStatus.BAD_REQUEST.value(), bindingResult.getAllErrors().get(0).getDefaultMessage());
    }


    private void handlerErrorMessage(Exception e) {
        logger.error(e.getMessage(), e);
    }

}